//
// Created by twlin on 2024/8/7.
//

#include "ctcpserver.h"
#include <sys/socket.h>
#include <cstring>
#include <string>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <fcntl.h>

#define MAX_LISTEN_QUE 5
#define SERV_PORT 8888
#define MAX_BUFFER_SIZE 255
#define MAX_EVENTS 500


CTcpServer *CTcpServer::_pInstance = nullptr;
std::mutex CTcpServer::_mutex;

CTcpServer::CTcpServer()
    : _listenfd(INVALID_SOCKET),
      _bRunning(true)
{

}

CTcpServer::~CTcpServer()
{
    for(auto so : _sockets)
        CSocket::close(so);

    CSocket::close(_listenfd);
}

CTcpServer *CTcpServer::getInstance()
{
    if (_pInstance == nullptr)
    {
        std::unique_lock<std::mutex> lock(_mutex); // 加锁
        if (_pInstance == nullptr)
        {
            volatile auto temp = new (std::nothrow) CTcpServer();
            _pInstance = temp;
        }
    }

    return _pInstance;
}

void CTcpServer::deleteInstance()
{
    std::unique_lock<std::mutex> lock(_mutex); // 加锁
    if (_pInstance)
    {
        delete _pInstance;
        _pInstance = nullptr;
    }
}

bool CTcpServer::startEpoll()
{
    int i;
    socket_t sockfd;
    int epollfd, fds;
    socklen_t len;
    struct epoll_event ev = {}, events[MAX_EVENTS];
    struct sockaddr_in client = {};


    len = sizeof(struct sockaddr_in);
    epollfd = epoll_create(MAX_EVENTS);
    if(epollfd < 0)
    {
        perror("epoll_create err:");
        return false;
    }

    if (mz_ipv4_tcp_create_socket() < 0)
    {
        return false;
    }

    fcntl(_listenfd, F_SETFL, O_NONBLOCK);

    ev.data.fd = _listenfd;
    ev.events = EPOLLIN;
    if(epoll_ctl(epollfd, EPOLL_CTL_ADD, _listenfd, &ev) < 0)
    {
        perror("epoll_ctl err:");
        return false;
    }

    while(_bRunning)
    {
        fds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
        if(fds < 0)
        {
//            if (errno == EINTR) {
//                continue; // 被信号中断，重新尝试
//            } else {
                perror("epoll_wait err:");
                return -1;
//            }
        }

        for(i = 0; i < fds; i++)
        {
            if(events[i].data.fd == _listenfd)
            {
                if((sockfd = CSocket::accept(_listenfd, (struct sockaddr *)&client, &len)) < 0)
                {
                    perror("accept error.\n");
                    continue;
                }
                ev.data.fd = sockfd;
                ev.events = EPOLLIN | EPOLLET;
                epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev);
                _sockets.push_back(sockfd);
                continue;
            }
            else
            {
                if(mz_process_data(events[i].data.fd) == -2)
                {
                    CSocket::close(events[i].data.fd);
                    _sockets.remove(events[i].data.fd);
                    epoll_ctl(epollfd, EPOLL_CTL_DEL, events[i].data.fd, &ev);
                    continue;
                }
            }
        }
    }

    close(epollfd);
    return true;
}

void CTcpServer::stopEpoll()
{
    _bRunning = false;
}

int CTcpServer::mz_ipv4_tcp_create_socket()
{
    int opt = 1;
    int len;
    struct sockaddr_in server = {};

    if((_listenfd = CSocket::create(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket error");
        return -1;
    }

    //设置地址为可重用
    if(!CSocket::setsockopt(_listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
    {
        perror("Create socket fail");
        return -1;
    }

    bzero(&server, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    server.sin_port = htons(SERV_PORT);

    len = sizeof(struct sockaddr_in);
    if(!CSocket::bind(_listenfd, (struct sockaddr *)&server, len))
    {
        perror("connect error");
        close(_listenfd);
        return -1;
    }

    CSocket::listen(_listenfd, MAX_LISTEN_QUE);
    return 0;
}

int CTcpServer::mz_process_data(int sockfd)
{
    int bytes;
    std::string str_buf;
    char tmp_buf[MAX_BUFFER_SIZE];
    char flag = 1;


    while(flag)
    {
        bzero(tmp_buf, MAX_BUFFER_SIZE);
        bytes = static_cast<int>(CSocket::recv(sockfd, tmp_buf, MAX_BUFFER_SIZE, 0));
        if(bytes < 0)
        {
            if(errno == EAGAIN)
            {
                printf("no data.\n");
                break;
            }
            perror("recv err:");
            return -1;
        }
        if(bytes == 0)
        {
//            if(errno != EWOULDBLOCK || errno != EAGAIN)
//            {
//                return -2;
//            }
            return -2;
        }
        if(bytes == MAX_BUFFER_SIZE && tmp_buf[bytes-1] != '\n')
        {
            flag = 1;
        }
        else
            flag = 0;

        str_buf += tmp_buf;

        printf("bytes: %d\n", bytes);
    }

    printf("buf: %s\n", str_buf.c_str());
    for(auto so : _sockets)
    {
        if (so != sockfd)
        {
            CSocket::send(so, str_buf.c_str(), str_buf.length(), 0);
        }
    }
    return 0;
}




